#include <57header.h>
#define BUFFER_SIZE (1024 * 1024 * 8)

/* Usage: ./04_mmapcpy src dest */
int main(int argc, char *argv[]){
    ARGS_CHECK(argc, 3);
    int src_fd = open(argv[1], O_RDONLY);
    ERROR_CHECK(src_fd, -1, "open src");

    // 获取源文件大小
    off_t src_size = lseek(src_fd, 0, SEEK_END);

    // 打开目标文件
    int dest_fd = 
        open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0666);
    ERROR_CHECK(dest_fd, -1, "open dest");

    // 为了避免在复制的过程中因为空间不足导致失败
    // 于是提前给dest目标文件占位置
    int ret = ftruncate(dest_fd, src_size);
    ERROR_CHECK(ret, -1, "ftruncate");

    // 开始进行mmap文件复制
    off_t bytes_copied = 0; // 记录已复制的字节大小
    while(bytes_copied < src_size){
        // src文件还没有复制完,继续复制
        // 1.确定这一轮mmap映射复制多少个字节
        off_t curr_cpy = 
            ((bytes_copied + BUFFER_SIZE) > src_size)?
            // 最后一次复制
            (src_size - bytes_copied):
            // 不是最后一次复制
            BUFFER_SIZE;

        // 2.分别映射源文件和目标文件
        void *srcp = mmap(NULL, curr_cpy, 
                          PROT_READ,MAP_SHARED,src_fd,
                          bytes_copied);
        ERROR_CHECK(srcp, MAP_FAILED, "mmap src");
        void *destp = mmap(NULL, curr_cpy, 
                          PROT_WRITE|PROT_READ,MAP_SHARED,dest_fd,
                          bytes_copied);
        ERROR_CHECK(destp, MAP_FAILED, "mmap dest");

        // 3.执行memcpy函数的内存复制操作(这就相当于文件复制)
        memcpy(destp, srcp, curr_cpy);  // 文件复制的核心操作
        // 4.这一轮映射结束后不要忘记解除映射,否则会导致内存泄露'
        munmap(srcp, curr_cpy);
        munmap(destp, curr_cpy);

        // 5.更新已复制的字节数
        bytes_copied += curr_cpy;
    }
    close(src_fd);
    close(dest_fd);
    return 0;
}

